package com.app.module.camera.core

import android.graphics.SurfaceTexture
import android.opengl.EGL14
import android.opengl.GLES20
import android.util.Log
import android.util.Size
import com.app.module.camera.core.provider.CameraProvider
import com.app.module.camera.core.provider.Provider
import com.app.module.camera.renderer.GLRenderer
import com.app.module.camera.renderer.base.DefaultRenderer
import com.app.module.camera.renderer.group.CameraRenderer
import com.app.module.camera.egl.EGLConfigAttrs
import com.app.module.camera.egl.EGLContextAttrs
import com.app.module.camera.egl.EGLHelper
import java.util.*

class DynamicProcessor : Observable {

    private var mGLThreadFlag: Boolean = false

    private lateinit var mGLThread: Thread

    private val dynamicProvider: Provider

    private val LOCK = Object()

    private val mRenderer: CameraRenderer = CameraRenderer(null)

    constructor(dynamicProvider: Provider) : super() {
        this.dynamicProvider = dynamicProvider
    }

    fun setRenderer(renderer: GLRenderer) {
        this.mRenderer.setGLRenderer(renderer)
    }

    fun getRenderer(): GLRenderer {
        return this.mRenderer.getGLRenderer() ?: DefaultRenderer()
    }

    fun start() {
        synchronized(LOCK) {
            if (!mGLThreadFlag) {
                mGLThreadFlag = true
                mGLThread = Thread(Runnable { glRun() })
                mGLThread.start()
                try {
                    LOCK.wait()
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
            }
        }
    }

    fun stop() {
        synchronized(LOCK) {
            if (mGLThreadFlag) {
                mGLThreadFlag = false
                dynamicProvider.close()
                try {
                    LOCK.wait()
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
            }
        }
    }

    fun switchCamera() {
        if (this.dynamicProvider is CameraProvider) {
            this.dynamicProvider.switchCamera()
            stop()
            start()
        }
    }

    private fun glRun() {
        val egl = EGLHelper()
        val ret = egl.createGLESWithSurface(EGLConfigAttrs(), EGLContextAttrs(), SurfaceTexture(1))
        if (!ret) {
            synchronized(LOCK) { LOCK.notifyAll() }
            return
        }
        // 创建一个ImageReader 得到他的surface , 将所有的绘制都在imagereader进行绘制 , 绘制完成后,得到其image的数据, 使用片元着色器直接进行渲染.
        val open = this.dynamicProvider.open()
        Log.e("Camera2Activity", "DynamicProcessor -> open  $open")
        val size = open.size
        val w = size.height
        val h = size.width
        val texture = open.texture
        val id = open.id
        if (w <= 0 || h <= 0) {
            destroyGL(egl)
            synchronized(LOCK) { LOCK.notifyAll() }
            return
        }
        // 通知其他线程
        synchronized(LOCK) { LOCK.notifyAll() }
        mRenderer.create()
        mRenderer.sizeChanged(w, h)
        mRenderer.setFlag(if (this.dynamicProvider.isLandscape()) CameraRenderer.TYPE_1379 else CameraRenderer.TYPE_7193)
        //用于其他的回调
        val rb = FrameBean(egl, Size(w, h), Thread.currentThread().id)
        val sourceFrame = FrameBuffer()
        //要求数据源必须同步填充SurfaceTexture，填充完成前等待
        while (!this.dynamicProvider.frame() && mGLThreadFlag) {
            texture.updateTexImage() // 更新像素
            texture.getTransformMatrix(mRenderer.getTextureMatrix())
            sourceFrame.bindFrameBuffer(w, h)
            GLES20.glViewport(0, 0, w, h)
            mRenderer.draw(id) //用作一个texture传入进行渲染
            sourceFrame.unBindFrameBuffer()
            rb.textureId = sourceFrame.getCacheTextureId()//接收数据源传入的时间戳
            rb.timeStamp = this.dynamicProvider.time()
            rb.textureTime = texture.timestamp
            notify(rb) // 通知其他进行展示和保存
        }
        synchronized(LOCK) {
            notify(rb.apply {
                endFlag = true
            })
            mRenderer.destroy()
            destroyGL(egl)
            LOCK.notifyAll()
        }
    }

    private fun destroyGL(egl: EGLHelper) {
        mGLThreadFlag = false
        EGL14.eglMakeCurrent(
            egl.getDisplay(),
            EGL14.EGL_NO_SURFACE,
            EGL14.EGL_NO_SURFACE,
            EGL14.EGL_NO_CONTEXT)
        EGL14.eglDestroyContext(egl.getDisplay(), egl.getDefaultContext())
        EGL14.eglTerminate(egl.getDisplay())
    }

    private fun notify(frame: FrameBean) {
        setChanged()
        notifyObservers(frame)
    }
}
